import http from 'http';
import url from 'url';
import qs from 'querystring';
import fetch from 'node-fetch';

const agent = new http.Agent({
    keepAlive: true,
    maxSockets: 500
});

const {
    name: projectName,
    version: projectVersion
} = require(`${think.ROOT_PATH}/package`);

function log(...args) {
    const {
        log: printlog
    } = think.config('transpond');
    printlog !== false && think.log(args.join(''), 'transpond:LOG');
}

function getTranspondOptions4rpc({
                                     host,
                                     port,
                                     path
                                 }) {
    const options = {
        href: url.format({
            protocol: 'http',
            hostname: host,
            port,
            pathname: path
        }),
        method: 'post',
        headers: {
            'Content-Type': 'application/json',
            'Transfer-Encoding': 'chunked',
            'User-Agent': `Node ${projectName} Version/${projectVersion}`,
        }
    };
    return options;
}

function getTranspondOptions4restful({
                                         host,
                                         port,
                                         path
                                     }, reqHeader, reqDate) {
    console.log(JSON.stringify(reqHeader))
    if (typeof reqHeader.path != 'string' || reqHeader.path[0] !== '/') {
        throw {
            message: '参数错误: path',
            errInfo: 'transpond:ERROR'
        };
    }

    const urlObj = url.parse(path + reqHeader.path);
    const isGet = String(reqHeader.method).toLowerCase() === 'get';
    if (isGet) {
        urlObj.query = think.extend({}, qs.parse(urlObj.query), reqDate);
    }

    const headers = reqHeader.headers || {
            'Content-Type': 'application/json;charSet=utf-8',
            // 'Transfer-Encoding': 'chunked',
            'User-Agent': `Node ${projectName} Version/${projectVersion}`,
            ...reqHeader.addheaders
        };

    delete headers.host;

    const options = {
        href: url.format({
            ...urlObj,
            protocol: 'http',
            hostname: host,
            port
        }),
        reqpath:reqHeader.path,
        method: reqHeader.method,
        headers
    };

    reqHeader.auth && (options.headers.authorization = reqHeader.auth);

    return options;
}

async function request4rpc(options, data, rawRes) {
    const sendData = JSON.stringify(data);
    log('req data: ' + sendData);

    let res;
    try {
        res = await fetch(options.href, {
            method: options.method,
            headers: options.header,
            body: sendData,
            agent
        });
    } catch (err) {
        think.log(err, 'ERROR');
        throw {
            errmsg: '请求转发出错',
            errInfo: 'transpond:ERROR'
        }
    }


    const statusCode = res.status;
    log(`statusCode: ${statusCode}`);

    if (rawRes) {
        return res;
    }

    let resData = null;
    try {
        resData = await res.clone().json();
    } catch (err) {
    }

    log(`res data: ${JSON.stringify(resData)}`);

    if (resData && resData.result === 0) {
        return resData;
    } else {
        let msg = '',
            info = null,
            errno = 1;
        if (resData) {
            msg = resData.resultNote;
            info = resData;
            errno = resData.result;
        } else {
            const text = await res.clone().text();

            throw {
                errInfo: 'transpond:ERROR',
                errmsg: '请求转发响应出错',
                text
            };
        }

        throw {
            errInfo: 'transpond:ERROR',
            errmsg: msg,
            errno: Number(errno),
            info
        };
    }
};

async function request4restful(options, data, rawRes) {
    const sendData = String(options.method).toLowerCase() !== 'get' && JSON.stringify(data.params);
    log('req data: ' + JSON.stringify(data.params));
    var key = "2d8dbcb5c0f66e260c1e2147efa33f1c";
    console.log('option is'+JSON.stringify(options))
    if (JSON.stringify(data.params) == "{}" || String(options.method).toLowerCase()== "get" ) {
        var sign = think.md5(think.config('transpond').rs.path + options.reqpath + key)
    }
    else {
        var sign = think.md5(JSON.stringify(data.params) + think.config('transpond').rs.path + options.reqpath +key)
    }
    // var crypto = require('crypto');
    // var md5 = crypto.createHash('md5');
    // var sign = md5.update(JSON.stringify(data.params)+options.href).digest('base64');
    // console.log("sign:"+sign);
    data.Identity = {}
    data.Identity.appCode = think.config('appinfo').appCode;
    data.Identity.serviceCode = think.config('appinfo').serviceCode;
    data.Identity.identityName = think.config('appinfo').identityName;
    data.Identity.identityKey = think.config('appinfo').identityKey;
    data.Identity.sign = sign;
    console.log('abc'+data.Identity )
    options.headers.Identity = JSON.stringify(data.Identity);

    console.log('header:' + JSON.stringify(options.headers));
    let res;
    try {
        res = await fetch(options.href, {
            method: options.method,
            headers: options.headers,
            body: sendData,
            agent
        });
    } catch (err) {
        think.log(err, 'ERROR');
        throw {
            errmsg: '请求转发出错',
            errInfo: 'transpond:ERROR'
        }
    }


    const statusCode = res.status;
    log(`statusCode: ${statusCode}`);

    if (rawRes) {
        return res;
    }

    let resData = null;
    try {
        resData = await res.json();
    } catch (err) {
    }

    log(`res data: ${JSON.stringify(resData)}`);

    if (res.ok) {
        return resData;
    } else {
        let msg = '',
            info = null,
            errno = statusCode;
        if (resData) {
            msg = resData.resultdesc;
            info = resData;
            errno += String(resData.resultcode);
        } else {
            const text = res._convert().toString();

            throw {
                errInfo: 'transpond:ERROR',
                errmsg: '请求转发响应出错',
                text
            };
        }

        throw {
            errInfo: 'transpond:ERROR',
            errmsg: msg,
            errno: Number(errno),
            info
        };
    }
}

//转发请求
export default class Transpond {
    constructor(conf = {}) {
        this.config = {
            ...conf
        };
        console.log(conf);
        this.apiType = conf.rs.apiType;
    }

    __request(data, auth, rawRes) {
        console.log("request");
        console.log(this.apiType);
        if (this.apiType === 'rpc') {
            const options = getTranspondOptions4rpc(this.config);
            log(`options: ${JSON.stringify(options)}`);
            if (!data.token && auth) {
                data.token = auth;
            }
            return request4rpc(options, data, rawRes);
        } else if (this.apiType === 'restful') {
            console.log("restful")
            const options = getTranspondOptions4restful(this.config.rs, {
                auth,
                ...data
            }, data.params);
            log(`options: ${JSON.stringify(options)}`);
            return request4restful(options, data, rawRes);
        }
    }

    async send(data, auth, rawRes = false) {
        console.log("send")
        if (!data) {
            throw {
                errmsg: '请求数据有误',
                errInfo: 'transpond:ERROR',
                data
            };
        }

        const mock = think.config('mock') || {};
        const mockKey = data.cmd || data.path;

        if (mock.on && mockKey in mock.data) {
            let mockItem = mock.data[mockKey];
            let mockData = typeof mockItem === 'function' ? mockItem(data) : mockItem;
            mockData = {
                ...mockData,
                ismock: true
            };

            return mockData;
        }
        console.log("sendend");
        return this.__request(data, auth, rawRes);
    }
}